package com.inesv.api.workers;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.inesv.api.baseclasses.BaseApi;
import com.inesv.api.baseclasses.BaseRpcSend;
import com.inesv.api.interfaces.EthMethodDefine;
import com.inesv.api.network.DefaultRPCSend;
import com.inesv.api.utils.HexUtil;
import com.inesv.api.utils.ValidateUtil;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

public class EthTokenAPi extends BaseApi implements EthMethodDefine {
    /**
     * 基础的构造函数  传递了钱包服务器的相关信息
     *
     * @param netRPCDefine rpc连接方式
     */
    public EthTokenAPi(BaseRpcSend netRPCDefine,String tokenAddress,String transMethodId,String balanceMethodId) {
        super(netRPCDefine);
        this.tokenAddress = tokenAddress;
        this.transMethodId = transMethodId;
        this.balanceMethodId = balanceMethodId;
    }
    public EthTokenAPi(String nodeRPCIP,String nodeRPCPort,String nodeRPCUser,String nodeRPCPassword,String tokenAddress, String transMethodId,String balanceMethodId){
        super(new DefaultRPCSend(nodeRPCIP,nodeRPCPort,nodeRPCUser,nodeRPCPassword));
        this.tokenAddress = tokenAddress;
        this.transMethodId = transMethodId;
        this.balanceMethodId = balanceMethodId;
    }
    public EthTokenAPi(BaseRpcSend netRPCDefine,BigDecimal wei,BigDecimal gas, BigDecimal gasPrice,String tokenAddress,String transMethodId,String balanceMethodId) {
        super(netRPCDefine);
        this.tokenAddress = tokenAddress;
        this.transMethodId = transMethodId;
        this.balanceMethodId = balanceMethodId;
        this.WEI = wei;
        this.gas = gas;
        this.gasPrice = gasPrice;
    }
    public EthTokenAPi(String nodeRPCIP,String nodeRPCPort,String nodeRPCUser,String nodeRPCPassword,BigDecimal wei,BigDecimal gas, BigDecimal gasPrice,String tokenAddress,String transMethodId,String balanceMethodId){
        super(new DefaultRPCSend(nodeRPCIP,nodeRPCPort,nodeRPCUser,nodeRPCPassword));
        this.tokenAddress = tokenAddress;
        this.transMethodId = transMethodId;
        this.balanceMethodId = balanceMethodId;
        this.WEI = wei;
        this.gas = gas;
        this.gasPrice = gasPrice;
    }
    @Override
    protected void initParam() {
        this.WEI = new BigDecimal("100000000");
        gas = null;
        gasPrice = null;
    }

    @Override
    public String getHeight() {
        String responseBody = getRPCResult("eth_blockNumber");
        return getRespponseResult(responseBody);
    }

    @Override
    public String sendTransaction(String from, String to, String value, String password) {
        if(tokenAddress == null || "".equals(tokenAddress) || transMethodId == null || "".equals(transMethodId)){
            return "";
        }
        //先解锁账号
        getRPCResult("personal_unlockAccount",from,password);
        //转账
        String data = transMethodId;
        data += ValidateUtil.strTo64(to.substring(to.indexOf("0x")+"0x".length()));
        data += ValidateUtil.strTo64(value.substring(value.indexOf("0x")+"0x".length()));
        Map<String, String> reqMap = new HashMap();
        reqMap.put("from", from);
        reqMap.put("to", tokenAddress);
        reqMap.put("data", data);
        if(gas != null) reqMap.put("gas", HexUtil.toSixTeenHex(gas.setScale(0,BigDecimal.ROUND_DOWN).toString()));
        if(gasPrice != null) reqMap.put("gasPrice", HexUtil.toSixTeenHex(gasPrice.setScale(0,BigDecimal.ROUND_DOWN).toString()));
        String rpcResponse = getRPCResult("eth_sendTransaction",reqMap);
        return getRespponseResult(rpcResponse);
    }

    @Override
    public String getTransactionList(String height) {
        String rpcResponse = getRPCResult("eth_getBlockByNumber",height,true);
        String result = getRespponseResult(rpcResponse);
        if(ValidateUtil.isNull(result)) {
            return "[]";
        }
        JSONObject jsonObject = JSONObject.parseObject(result);
        if(jsonObject == null){
            return "[]";
        }
        JSONArray array = jsonObject.getJSONArray("transactions");
        return array == null ? "[]":array.toJSONString();
    }

    @Override
    public String getBalance(String address) {
        String paramsDatAddress = address.substring(address.indexOf("0x")+"0x".length());
        StringBuffer strTo64 = ValidateUtil.strTo64(paramsDatAddress);
        String data = balanceMethodId + strTo64.toString();
        Map<String, String> param = new HashMap(5);
        param.put("from", address);
        param.put("to", tokenAddress);
        param.put("data", data);
        param.put("value", "0x0");
        String resoponseBody = getRPCResult("eth_call",param,"latest");
        if(resoponseBody == null || "".equals(resoponseBody)){
            return "0x0";
        }
        String result = getRespponseResult(resoponseBody);
        if(result == null || "".equals(result)){
            return "0x0";
        }
        return result;
    }

    @Override
    public String newAddress(String flag) {
        String response = getRPCResult("personal_newAccount",flag);
        return getRespponseResult(response);
    }

    @Override
    public String getTransactionByHash(String hash) {
        String rpcResponse = getRPCResult("eth_getTransactionByHash",hash);
        return getRespponseResult(rpcResponse);
    }

    @Override
    public String getGasAndGasPrice(String outAddress, String inAddress, String value) {
        if(gas != null && gasPrice != null){
            return HexUtil.toSixTeenHex(gas.multiply(gasPrice).setScale(0,BigDecimal.ROUND_DOWN).toString());
        }
        Map<String, String> reqMap = new HashMap<>();
        reqMap.put("from", outAddress);
        reqMap.put("to", inAddress);
        reqMap.put("value", value);
        if(gas != null)reqMap.put("gas", HexUtil.toSixTeenHex(gas.setScale(0,BigDecimal.ROUND_DOWN).toString()));
        if(gasPrice != null)reqMap.put("gasPrice", HexUtil.toSixTeenHex(gasPrice.setScale(0,BigDecimal.ROUND_DOWN).toString()));
        String gas_get = gas == null?
                getRespponseResult(getRPCResult("eth_estimateGas", reqMap)):
                HexUtil.toSixTeenHex(gas.setScale(0,BigDecimal.ROUND_DOWN).toString());
        String gasPrice_get = gasPrice == null?
                getRespponseResult(getRPCResult("eth_gasPrice", reqMap)):
                HexUtil.toSixTeenHex(gasPrice.setScale(0,BigDecimal.ROUND_DOWN).toString());
        if(gas == null && ValidateUtil.isNull(gas_get)){
            return HexUtil.toSixTeenHex("0");
        }
        if(ValidateUtil.isNull(gasPrice_get)){
            return HexUtil.toSixTeenHex(new BigDecimal("90000").multiply(gas).toString());
        }
        BigDecimal gasGet = new BigDecimal(HexUtil.toTenHex(gas_get));
        BigDecimal gasPriceGet = new BigDecimal(HexUtil.toTenHex(gasPrice_get));
        return HexUtil.toSixTeenHex(gasGet.multiply(gasPriceGet).setScale(0,BigDecimal.ROUND_DOWN).toString());
    }

    /**
     * 根据需要的信息，调用rpc方法，获取结果
     * @param method
     * @param params
     * @return
     */
    protected String getRPCResult(String method,Object... params){
        String requestBody = new String(netRPCDefine.prepareRequest(method,params));
        return netRPCDefine.generateRequest(requestBody,netRPCDefine.getNodeUri());
    }

    /**
     * 根据rpc返回结果获取result的json数据
     * @param rpcResponse  rpc返回结果
     * @return  结果中result的json数据
     */
    protected String getRespponseResult(String rpcResponse){
        if(!ValidateUtil.isNull(rpcResponse)){
            JSONObject jsonObject = JSONObject.parseObject(rpcResponse);
            if(jsonObject.containsKey("result")){
                return jsonObject.getString("result");
            }
        }
        return "";
    }
}
